package com.example.onlineanswer.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.onlineanswer.common.api.ResultCode;
import com.example.onlineanswer.common.exception.ApiException;
import com.example.onlineanswer.mapper.*;
import com.example.onlineanswer.model.entity.AnswerRecord;
import com.example.onlineanswer.model.entity.Contest;
import com.example.onlineanswer.model.entity.Question;
import com.example.onlineanswer.model.entity.Participation;
import com.example.onlineanswer.model.vo.ContestAnswerVO;
import com.example.onlineanswer.model.vo.ContestVO;
import com.example.onlineanswer.model.vo.UserAnswerVO;
import com.example.onlineanswer.service.ContestService;
import com.example.onlineanswer.service.ParticipationService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 竞赛服务实现类
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class ContestServiceImpl extends ServiceImpl<ContestMapper, Contest> implements ContestService {

    private final ContestMapper contestMapper;
    private final QuestionMapper questionMapper;
    private final AnswerMapper answerMapper;
    private final ParticipationMapper participationMapper;
    private final ParticipationService participationService;
    private final AnswerRecordMapper answerRecordMapper;

    @Override
    public IPage<ContestVO> pageContestList(Page<ContestVO> page, Integer status, Integer excludeStatus, String keyword, Long creatorId) {
        return contestMapper.pageContestList(page, status, excludeStatus, keyword, creatorId);
    }

    @Override
    public ContestVO getContestDetailById(Long id) {
        return contestMapper.getContestDetailById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createContest(Contest contest) {
        // 设置初始状态为待审核
        contest.setStatus(0);
        contest.setCurrentParticipants(0);
        contest.setCreateTime(LocalDateTime.now());
        contest.setUpdateTime(LocalDateTime.now());
        
        save(contest);
        return contest.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateContest(Contest contest) {
        // 只有待审核和已拒绝状态的竞赛可以修改
        Contest dbContest = getById(contest.getId());
        if (dbContest == null || (dbContest.getStatus() != 0 && dbContest.getStatus() != 3)) {
            return false;
        }
        
        contest.setUpdateTime(LocalDateTime.now());
        // 修改后状态变为待审核
        contest.setStatus(0);
        
        return updateById(contest);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean reviewContest(Long id, Integer status, Long reviewerId) {
        Contest contest = getById(id);
        if (contest == null) {
            return false;
        }
        
        contest.setStatus(status);
        contest.setReviewerId(reviewerId);
        contest.setReviewTime(LocalDateTime.now());
        contest.setUpdateTime(LocalDateTime.now());
        
        return updateById(contest);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteContest(Long id) {
        // 逻辑删除
        return removeById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean startContest(Long id) {
        Contest contest = getById(id);
        if (contest == null || contest.getStatus() != 2) {
            // 只有已审核待开始的竞赛可以开始
            return false;
        }
        
        // 检查是否有题目
        int questionCount = questionMapper.getQuestionCountByContestId(id);
        if (questionCount == 0) {
            return false;
        }
        
        contest.setStatus(1);  // 进行中
        contest.setStartTime(LocalDateTime.now());
        contest.setUpdateTime(LocalDateTime.now());
        
        // 保存竞赛状态
        boolean updateResult = updateById(contest);
        if (!updateResult) {
            return false;
        }
        
        // 设置第一个题目为当前题目
        try {
            // 获取第一个题目
            List<Question> questions = questionMapper.getQuestionsByContestId(id);
            if (questions != null && !questions.isEmpty()) {
                // 获取排序号为1的题目，如果没有则获取第一个题目
                Question firstQuestion = questions.stream()
                        .filter(q -> q.getOrderNum() == 1 || q.getOrderNum() == 0)
                        .findFirst()
                        .orElse(questions.get(0));
                
                // 设置为当前题目
                contest.setCurrentQuestionId(firstQuestion.getId());
                updateById(contest);
            }
        } catch (Exception e) {
            log.error("设置第一个题目失败: {}", e);
            // 不影响竞赛开始
        }
        
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean endContest(Long id) {
        Contest contest = getById(id);
        if (contest == null || contest.getStatus() != 1) {
            // 只有进行中的竞赛可以结束
            return false;
        }
        
        contest.setStatus(4);  // 已结束
        contest.setEndTime(LocalDateTime.now());
        contest.setUpdateTime(LocalDateTime.now());
        
        return updateById(contest);
    }

    @Override
    public boolean updateParticipants(Long id, int incrementValue) {
        return contestMapper.updateParticipants(id, incrementValue) > 0;
    }

    @Override
    public boolean updateCurrentQuestionId(Long id, Long currentQuestionId) {
        Contest contest = getById(id);
        if (contest == null) {
            return false;
        }
        contest.setCurrentQuestionId(currentQuestionId);
        return updateById(contest);
    }

    @Override
    public ContestAnswerVO getContestAnswerStatistics(Long contestId) {
        // 获取竞赛基本信息
        ContestVO contestVO = contestMapper.getContestDetailById(contestId);
        if (contestVO == null) {
            return null;
        }
        
        // 构建返回结果
        ContestAnswerVO result = new ContestAnswerVO();
        result.setContestId(contestVO.getId());
        result.setContestName(contestVO.getTitle());
        result.setDescription(contestVO.getDescription());
        result.setStartTime(contestVO.getStartTime());
        result.setEndTime(contestVO.getEndTime());
        
        // 此处需要从答题表中统计数据
        // 可以通过SQL查询或在AnswerMapper中添加相应方法来实现
        // 此处仅提供示例实现
        // TODO: 实现答题统计数据的查询逻辑
        
        // 查询所有答题记录
        Page<UserAnswerVO> page = new Page<>(1, 100);  // 分页参数
        IPage<UserAnswerVO> answerPage = answerMapper.pageContestAnswers(page, contestId, null, null, null);
        List<UserAnswerVO> answerList = answerPage.getRecords();
        
        // 设置答题列表
        result.setAnswerList(answerList);
        
        // 统计数据
        int totalAnswers = answerList.size();
        int correctAnswers = (int) answerList.stream().filter(UserAnswerVO::getIsCorrect).count();
        double averageScore = answerList.stream()
                .mapToInt(UserAnswerVO::getScore)
                .average()
                .orElse(0.0);
        
        result.setAnswerCount(totalAnswers);
        result.setCorrectCount(correctAnswers);
        result.setAverageScore(averageScore);
        
        // 统计用户数量（去重）
        long userCount = answerList.stream()
                .map(UserAnswerVO::getUserId)
                .distinct()
                .count();
        result.setUserCount((int) userCount);
        
        return result;
    }

    @Override
    public boolean isUserJoined(Long contestId, Long userId) {
        // 检查竞赛是否存在
        Contest contest = getById(contestId);
        if (contest == null) {
            return false;
        }
        
        // 从参赛记录表中查询是否有记录
        Long participationId = participationMapper.checkUserParticipation(contestId, userId);
        
        // 如果有参赛记录，表示已参与
        return participationId != null;
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean joinContest(Long contestId, Long userId) {
        // 检查竞赛是否存在
        Contest contest = getById(contestId);
        if (contest == null) {
            throw new ApiException("竞赛不存在");
        }
        
        // 检查竞赛状态是否为已通过
        if (contest.getStatus() != 1) {
            throw new ApiException("竞赛未开始或已结束，无法参与");
        }
        
        // 检查是否已参与
        if (isUserJoined(contestId, userId)) {
            throw new ApiException("您已参与此竞赛");
        }
        
        // 检查参与人数是否达到上限
        if (contest.getParticipantLimit() != null && contest.getCurrentParticipants() >= contest.getParticipantLimit()) {
            throw new ApiException("参与人数已达上限");
        }
        
        // 检查是否距离开始时间不足10分钟
        if (contest.getStartTime() != null) {
            LocalDateTime now = LocalDateTime.now();
            LocalDateTime startTime = contest.getStartTime();
            long minutesDiff = java.time.Duration.between(now, startTime).toMinutes();
            
            if (minutesDiff >= 0 && minutesDiff < 10) {
                throw new ApiException("距离竞赛开始不足10分钟，无法参与");
            }
        }
        
        try {
            // 创建参赛记录
            Participation participation = new Participation();
            participation.setUserId(userId);
            participation.setContestId(contestId);
            participation.setJoinTime(LocalDateTime.now());
            participation.setTotalScore(0);
            participation.setCreateTime(LocalDateTime.now());
            participation.setUpdateTime(LocalDateTime.now());
            participation.setStatus(1); // 正常参与
            
            // 保存参赛记录
            boolean saveResult = participationService.save(participation);
            if (!saveResult) {
                throw new ApiException("创建参赛记录失败");
            }
            
            // 更新竞赛参与人数
            boolean updateResult = updateParticipants(contestId, 1);
            if (!updateResult) {
                throw new ApiException("更新竞赛参与人数失败");
            }
            
            return true;
        } catch (Exception e) {
            log.error("参与竞赛异常: {}", e.getMessage(), e);
            throw new ApiException("参与竞赛失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void finalizeContestResults(Long contestId) {
        log.info("开始为竞赛ID {} 计算最终结果...", contestId);

        // 1. 获取该竞赛的所有有效参与记录
        List<Participation> participations = participationMapper.selectList(
            new LambdaQueryWrapper<Participation>()
                .eq(Participation::getContestId, contestId)
                .eq(Participation::getStatus, 1) // 正常参与
        );

        if (participations.isEmpty()) {
            log.info("竞赛ID {} 没有有效的参与记录，无需计算结果。", contestId);
            return;
        }

        log.info("竞赛ID {} 找到了 {} 条有效参与记录。", contestId, participations.size());

        // 2. 为每个参与记录计算总分
        for (Participation participation : participations) {
            List<AnswerRecord> answerRecords = answerRecordMapper.selectList(
                new LambdaQueryWrapper<AnswerRecord>()
                    .eq(AnswerRecord::getParticipationId, participation.getId())
            );
            
            int totalScore = 0;
            if (answerRecords != null && !answerRecords.isEmpty()) {
                totalScore = answerRecords.stream()
                                .filter(ar -> ar.getScore() != null)
                                .mapToInt(AnswerRecord::getScore)
                                .sum();
            }
            participation.setTotalScore(totalScore);
            log.debug("用户ID {} 在竞赛ID {} 的总分计算为: {}", participation.getUserId(), contestId, totalScore);
        }

        // 3. 根据总分对参与记录进行排序 (降序)
        participations.sort(Comparator.comparingInt(Participation::getTotalScore).reversed());

        // 4. 分配排名并准备更新
        int currentRank = 1;
        for (int i = 0; i < participations.size(); i++) {
            Participation participation = participations.get(i);
            // 处理并列排名：如果当前分数与前一名相同，则排名相同
            if (i > 0 && participation.getTotalScore().equals(participations.get(i - 1).getTotalScore())) {
                participation.setRank(participations.get(i - 1).getRank());
            } else {
                participation.setRank(currentRank);
            }
            currentRank++; // 无论是否并列，下一个可能的排名总是增加
            participation.setUpdateTime(LocalDateTime.now());

            // 更新单个参与记录 (也可以收集起来批量更新，但单个更新更简单直观)
            participationMapper.updateById(participation);
            log.debug("更新用户ID {} 在竞赛ID {} 的最终排名: {}, 总分: {}",
                    participation.getUserId(), contestId, participation.getRank(), participation.getTotalScore());
        }
        log.info("竞赛ID {} 的所有参与记录的总分和排名已更新完毕。", contestId);
    }
} 